﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using WW.NActiveRecord.ConnectionAdapters.SqlServer;
using WW.NActiveRecord.ContractExceptions;
using WW.NActiveRecord.Internal.Utils;

namespace WW.NActiveRecord.Internal
{
    /// <summary>
    /// 内部类，一个小的对象包装
    /// </summary>
    class MappingEntity {
        private readonly Type entityType;
        private readonly MetaDataTable table;
        private Dictionary<string, MappingMember> members = new Dictionary<string, MappingMember>(CaseInsensitiveComparer2.Default);

        internal MappingEntity(Type entityType, MetaDataTable table) {
            this.entityType = entityType;
            this.table = table;
            
            entityType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                .Where(f => f.FieldType.IsGenericType && typeof(IEntityMember).IsAssignableFrom(f.FieldType))
                .ToList().ForEach(fieldInfo =>
                                      {
                                          //实体成员IEntityMember字段必须设置为readonly
                                          //因为重新赋值将破坏初始化方法
                                          if(!fieldInfo.IsInitOnly){
                                              throw new EntityMemberNotReadonly(fieldInfo);
                                          }
                                          Add(fieldInfo);
                                      });


            //entityType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
            //    .Where(f => f.FieldType.IsGenericType && typeof(EntityMember).IsAssignableFrom(f.FieldType))
            //    .ToList().ForEach(fieldInfo => Add(fieldInfo));
        }

        public MetaDataTable Table {
            get { return table; }
        }

        public Type EntityType {
            get { return entityType; }
        }

        public Dictionary<string, MappingMember> Members {
            get { return members; }
            set { members = value; }
        }

        private void Add(FieldInfo f) {
            //普通实体字段必须对应表中相应的列,TODO 实体引用的外健检查
            if (f.FieldType.GetGenericTypeDefinition() == typeof(MemberField<>) && !table.Contains(f.Name)) {
                throw new ColumnMismatchException(f);
            }

            if (f.FieldType.GetGenericTypeDefinition() == typeof(MemberField<>) && table.Contains(f.Name)) {
                members.Add(f.Name, new MappingMember(f, Table.Columns[f.Name]));
            } else {
                //TODO 引用对象如何处理? attribute?
                members.Add(f.Name, new MappingMember(f, null));
            }
        }

        public void InitMember(Entity entity) {
            foreach (var member in members.Values) {
                member.Init(entity);
            }
        }
    }

    class MappingMember {
        private readonly FieldInfo field;
        private readonly MetaDataColumn column;

        public MappingMember(FieldInfo field, MetaDataColumn column) {
            this.field = field;
            this.column = column;
        }

        public MetaDataColumn Column {
            get { return column; }
        }

        public FieldInfo Field {
            get { return field; }
        }

        public Type FieldType {
            get { return Field.FieldType.GetGenericArguments()[0]; }
        }

        public void Init(Entity entity) {
            object value = field.GetValue(entity);
            if (value == null) {
                throw new EntityMappingFieldNotInstantiatedException(field);
            }
            //实体字段需要知道自己是谁,属于谁
            ((IEntityMember)value).Init(field, entity);
        }

        public override string ToString() {
            return string.Format("{{field:{0},column:}}", field);
        }
    }
}